package com.wtf.dsp.admin.hanlder;


import com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException;
import com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException;
import com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;
import com.wtf.dsp.admin.enums.CommonErrorEnum;
import com.wtf.dsp.admin.exception.WtfDspException;
import com.wtf.dsp.admin.util.MdcUtil;
import com.wtf.dsp.core.api.R;
import com.zaxxer.hikari.pool.HikariPool;
import lombok.extern.slf4j.Slf4j;
import org.postgresql.util.PSQLException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Set;

/**
 * 全局处理异常
 * date: 2022/6/18 10:59
 * @author linhuanyou
 * @email 496558736@qq.com
 * @version 1.0
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R handleException(Exception e) {
        log.error("Exception error", e);
       return handleError(null);
    }

    private R handleError(CommonErrorEnum commonErrorEnum) {
        R r = commonErrorEnum == null ? R.error() : R.error(commonErrorEnum.getErrCode(), commonErrorEnum.getErrMsg());
        r.setRequestId(MdcUtil.getLogMid());
        return r;
    }

    private R handleError(int code ,String msg) {
        R r = R.error(code, msg);
        r.setRequestId(MdcUtil.getLogMid());
        return r;
    }

    @ResponseBody
    @ExceptionHandler(RuntimeException.class)
    public R handleRuntimeException(RuntimeException e){
        log.error("RuntimeException error", e);
        return handleError(CommonErrorEnum.OPERATION_ERRO);
    }

    @ResponseBody
    @ExceptionHandler(IncorrectResultSizeDataAccessException.class)
    public R handleIncorrectResultSizeDataAccessException(IncorrectResultSizeDataAccessException e){
        log.error("IncorrectResultSizeDataAccessException error", e);
        return handleError(CommonErrorEnum.EXECUTOR_SQL_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(HikariPool.PoolInitializationException.class)
    public R handlePoolInitializationException(HikariPool.PoolInitializationException e){
        log.error("HikariPool.PoolInitializationException error", e);
        return handleError(CommonErrorEnum.HIKARI_POOL_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(MySQLNonTransientConnectionException.class)
    public R handleMySQLNonTransientConnectionException(MySQLNonTransientConnectionException e){
        log.error("MySQLNonTransientConnectionException error", e);
        return handleError(CommonErrorEnum.EXECUTOR_SQL_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(DataIntegrityViolationException.class)
    public R handleDataIntegrityViolationException(DataIntegrityViolationException e){
        log.error("DataIntegrityViolationException error", e);
        return handleError(CommonErrorEnum.EXECUTOR_SQL_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(BadSqlGrammarException.class)
    public R handleBadSqlGrammarException(BadSqlGrammarException e){
        log.error("BadSqlGrammarException error", e);
        return handleError(CommonErrorEnum.EXECUTOR_SQL_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(MySQLSyntaxErrorException.class)
    public R handleMySQLSyntaxErrorException(MySQLSyntaxErrorException e){
        log.error("MySQLSyntaxErrorException error", e);
        return handleError(CommonErrorEnum.EXECUTOR_SQL_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(WtfDspException.class)
    public R handleWtfDspException(WtfDspException e){
        log.error("WtfDspException error", e);
        return handleError(e.getErrCode(),e.getErrMsg());
    }

    @ResponseBody
    @ExceptionHandler(IllegalArgumentException.class )
    public R handleIllegalArgumentException (IllegalArgumentException e){
        log.error( "IllegalArgumentException error", e );
        return handleError(CommonErrorEnum.ERROR_VALID.getErrCode(),e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(SQLException.class)
    public R handleSQLException(SQLException e){
        log.error("SQLException error", e);
        return handleError(CommonErrorEnum.ERROR_DB.getErrCode(),e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(PSQLException.class)
    public R handlePSQLException(PSQLException e){
        log.error("PSQLException error", e);
        return handleError(CommonErrorEnum.ERROR_DB);
    }
    
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class )
    public R handleMethodArgumentNotValidException (MethodArgumentNotValidException e ){
        log.error( "MethodArgumentNotValidException error", e );
        String errorMsg = "";
        for (FieldError error : e.getBindingResult().getFieldErrors()) {
            errorMsg = error.getDefaultMessage();
            break;
        }
        return handleError(CommonErrorEnum.ERROR_VALID.getErrCode(),e.getMessage());
    }

    @ExceptionHandler(ConstraintViolationException.class )
    public R handleConstraintViolationException (ConstraintViolationException e ){
        log.error( "ConstraintViolationException error", e );
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        String errorMsg = "";
        for (ConstraintViolation error : constraintViolations) {
            errorMsg = error.getMessageTemplate();
            break;
        }
        return handleError(CommonErrorEnum.ERROR_VALID.getErrCode(),e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(BindException.class )
    public R handleMethodArgumentNotValidException (BindException e ){
        log.error( "MethodBindException error", e );
        String errorMsg = "";
        for (FieldError error : e.getBindingResult().getFieldErrors()) {
            errorMsg = error.getDefaultMessage();
            break;
        }
        return handleError(CommonErrorEnum.ERROR_VALID.getErrCode(),e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(IOException.class )
    public R handleIOException (IOException e){
        log.error( "IOException error", e );
        return handleError(CommonErrorEnum.ERROR_NETWORK);
    }
    
    @ResponseBody
    @ExceptionHandler(CannotFindDataSourceException.class )
    public R handleCannotFindDataSourceException (CannotFindDataSourceException e){
        log.error( "CannotFindDataSourceException error", e );
        return handleError(CommonErrorEnum.ERROR_NOT_FIND_DS);
    }
    
    @ResponseBody
    @ExceptionHandler(NullPointerException.class )
    public R handleNullPointerException (NullPointerException e){
        log.error( "NullPointerException error", e );
        return handleError(CommonErrorEnum.ERROR_NULL);
    }
    
    @ResponseBody
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class )
    public R handleHttpRequestMethodNotSupportedException (HttpRequestMethodNotSupportedException e){
        log.error( "HttpRequestMethodNotSupportedException error", e );
        return handleError(CommonErrorEnum.ERROR_REQUEST_METHOD_NOT_SUPPORTED);
    }

    @ResponseBody
    @ExceptionHandler(DuplicateKeyException.class )
    public R handleDuplicateKeyException (DuplicateKeyException e){
        log.error( "DuplicateKeyException error", e );
        return handleError(CommonErrorEnum.ERROR_DUPLICATE_KEY);
    }
}
